
    /**  
    * @Title: WxMessageUtil.java
    * @Package com.third.wx.gzh.util
    * @Description: 
    * @author likai
    * @date 2017年8月2日
    * @version V1.0  
    */
    
package com.third.base.wx;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.third.utils.wx.WxConfig;
import com.utils.date.CalendarUtil;
import com.utils.transtype.TransType;
 
//import com.souvc.weixin.message.resp.Article;
//import com.souvc.weixin.message.resp.ImageMessage;
//import com.souvc.weixin.message.resp.MusicMessage;
//import com.souvc.weixin.message.resp.NewsMessage;
//import com.souvc.weixin.message.resp.TextMessage;
//import com.souvc.weixin.message.resp.VideoMessage;
//import com.souvc.weixin.message.resp.VoiceMessage;
//import com.thoughtworks.xstream.XStream;
//import com.thoughtworks.xstream.core.util.QuickWriter;
//import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
//import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
//import com.thoughtworks.xstream.io.xml.XppDriver;

    /**
    * @ClassName: WxMessageUtil
    * @Description: 微信公众号消息处理
    * @author likai
    * @date 2017年8月2日
    *
    */

public class WxGzhMessageUtil{
	public static Logger log = LoggerFactory.getLogger(WxGzhMessageUtil.class);
	// 请求消息类型：文本
    public static final String REQ_MESSAGE_TYPE_TEXT = "text";
    // 请求消息类型：图片
    public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
    // 请求消息类型：语音
    public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
    // 请求消息类型：视频
    public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
    // 请求消息类型：小视频
    public static final String REQ_MESSAGE_TYPE_SHORTVIDEO = "shortvideo";
    // 请求消息类型：地理位置
    public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
    // 请求消息类型：链接
    public static final String REQ_MESSAGE_TYPE_LINK = "link";
 
    // 请求消息类型：事件推送
    public static final String REQ_MESSAGE_TYPE_EVENT = "event";
 
    // 事件类型：subscribe(订阅),关注公众号事件
    public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
    // 事件类型：unsubscribe(取消关注公众号事件)
    public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
    // 事件类型：scan(用户已关注时的扫描带参数二维码)
    public static final String EVENT_TYPE_SCAN = "scan";
    // 事件类型：LOCATION(上报地理位置)
    public static final String EVENT_TYPE_LOCATION = "location";
    // 事件类型：CLICK(自定义菜单)
    public static final String EVENT_TYPE_CLICK = "click";
 
    // 响应消息类型：文本
    public static final String RESP_MESSAGE_TYPE_TEXT = "text";
    // 响应消息类型：图片
    public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
    // 响应消息类型：语音
    public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
    // 响应消息类型：视频
    public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
    // 响应消息类型：音乐
    public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
    // 响应消息类型：图文
    public static final String RESP_MESSAGE_TYPE_NEWS = "news";
 
    /**
     * 解析微信发来的请求
     * 
     * @param request
     * @return Map
     * @throws Exception
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static  WxGzhMessge getWxReturn(HttpServletRequest request,WxConfig wxConfig)  {
        // 将解析结果存储在HashMap中
        InputStream inputStream =null;
        try {
        	 // 从request中取得输入流
            inputStream = request.getInputStream();
            // 读取输入流
            SAXReader reader = newSAXReader();          
            Document document = reader.read(inputStream);
            // 得到xml根元素
            Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();
            Map<String,Object> data = new HashMap(); 
            // 遍历所有子节点
            for (Element e : elementList)
            	data.put(e.getName(), e.getText());
            WxGzhMessge wxMessge=null;
            if (wxConfig.isEncrypt()) {
				//消息解密
            	 wxMessge=decryptMsg(data, wxConfig);
			}else {
				 wxMessge=TransType.mapToBean(WxGzhMessge.class, data);
			}
            // 释放资源
            inputStream.close();
            inputStream = null;		
            return wxMessge;
		} catch (Exception e) {
			 return null;
		}
    }
    
 
    @SuppressWarnings("unchecked")
	public static WxGzhMessge decryptMsg(Map<String,Object> msg,WxConfig wxConfig) throws AesException {
    	WXBizMsgCrypt pc = new WXBizMsgCrypt(wxConfig.getToken(), wxConfig.getEncodingAesKey(), wxConfig.getAppID());
    	log.info(msg.toString());
    	String encrypt = (String) msg.get("Encrypt");//密文
    	String msgSignature = (String) msg.get("MsgSignature");//签名
    	String timeStamp = (String) msg.get("TimeStamp");//签名
    	String nonce = (String) msg.get("Nonce");//签名
    	String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";
		String fromXML = String.format(format, encrypt);
		String result2 = pc.decryptMsg(msgSignature, timeStamp, nonce, fromXML);
		WxGzhMessge wxMessge=TransType.mapToBean(WxGzhMessge.class, TransType.xmlToMap(result2));
		return wxMessge;
	}
    
    /**
     * 回复微信文本消息
     * 
     * @param request
     * @return Map
     * @throws AesException 
     * @throws Exception
     */
    public static String getTextReturn(Map<String, String> param,WxConfig wxConfig)  {
    	
    	StringBuffer str = new StringBuffer();  
        str.append("<xml>");  
        str.append("<ToUserName><![CDATA[" + param.get("ToUserName") + "]]></ToUserName>");  
        str.append("<FromUserName><![CDATA[" + param.get("FromUserName") + "]]></FromUserName>");  
        str.append("<CreateTime>" + CalendarUtil.getShortTime() + "</CreateTime>");  
        str.append("<MsgType><![CDATA[text]]></MsgType>");  
        str.append("<Content><![CDATA["+param.get("Content")+"]]></Content>");  
        str.append("</xml>");  
        if (wxConfig.isEncrypt()) {
    		String mingwen;
			try {
				WXBizMsgCrypt pc = new WXBizMsgCrypt(wxConfig.getToken(), wxConfig.getEncodingAesKey(), wxConfig.getAppID());
				mingwen = pc.encryptMsg(str.toString(), CalendarUtil.getShortTime()+"", "ac0fcb74fb1f4");
				return mingwen;
			} catch (AesException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
        return str.toString();
	}
    
    /**
     * xml禁用外部实体类，防止XEE攻击
     * @return
     * @throws SAXException 
     */
    public static SAXReader newSAXReader() throws SAXException{
    	SAXReader reader = new SAXReader();
    	reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    	reader.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
    	reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
    	reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    	reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        return reader;
    }
}
